package net.cassite.daf4j.ds;

import net.cassite.daf4j.*;

import java.util.List;
import java.util.Map;

/**
 * DataAccess数据源<br>
 * 使用DataSource来简化DataAccess和避免DataAccess的开发中的失误
 *
 * @param <Context>      上下文
 * @param <BasicElement> 基本元素
 */
public class DataSource<Context, BasicElement, DS> implements DataAccess {
        private final AroundParser<Context, BasicElement, DS> aroundParser;
        private final DS source;

        private final ParserPacket<Context, BasicElement, DS> parserPacket;

        private final TxManager txManager;

        protected DataSource(ConditionParser<Context, BasicElement> conditionParser,
                             ExpressionParser<Context, BasicElement> expressionParser,
                             AndOrParser<Context, BasicElement> andOrParser,
                             AroundParser<Context, BasicElement, DS> aroundParser,
                             QueryParameterParser<Context, BasicElement> queryParameterParser,
                             EntityDataParser<Context, BasicElement> entityDataParser,
                             UpdateEntryParser<Context, BasicElement> updateEntryParser,
                             TxManager txManager,
                             DS source) {
                this.aroundParser = aroundParser;
                this.txManager = txManager;
                this.source = source;

                ConditionResolver<Context, BasicElement> conditionResolver = new ConditionResolver<Context, BasicElement>(conditionParser);
                ExpressionResolver<Context, BasicElement> expressionResolver = new ExpressionResolver<Context, BasicElement>(expressionParser);

                parserPacket = new ParserPacket<Context, BasicElement, DS>(andOrParser,
                        aroundParser, conditionParser, entityDataParser, expressionParser, queryParameterParser, updateEntryParser, txManager);

                aroundParser.setParserPacket(parserPacket);

                ObjectResolver<Context, BasicElement> objectResolver = new ObjectResolver<Context, BasicElement>(conditionResolver, expressionResolver, parserPacket);

                parserPacket.setResolvers(conditionResolver, expressionResolver, objectResolver);

                andOrParser.setObjectResolver(objectResolver);

                this.aroundParser.setObjectResolver(objectResolver);

                queryParameterParser.setObjectResolver(objectResolver);

                updateEntryParser.setObjectResolver(objectResolver);

                conditionParser.setObjectResolver(objectResolver);

                expressionParser.setObjectResolver(objectResolver);
        }

        @Override
        public <En> En find(Class<En> entityClass, Object pkValue) {
                try {
                        return aroundParser.find(source, entityClass, pkValue);
                } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }


        @SuppressWarnings("unchecked")
        @Override
        public <En> List<En> list(En entity, Where whereClause, QueryParameter parameter) {
                try {
                        Context context = aroundParser.initiateList(source, entity, whereClause, parameter);
                        DSUtils.listGenerationProcess(context, whereClause, parameter, parserPacket);
                        return (List<En>) aroundParser.executeList(context);
                } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }

        @Override
        public List<Map<String, Object>> projection(Object entity, Where whereClause, QueryParameterWithFocus parameter) {
                try {
                        Context context = aroundParser.initiateProjection(source, entity, whereClause, parameter);
                        DSUtils.projectionGenerationProcess(context, whereClause, parameter, parserPacket);
                        return aroundParser.executeProjection(context);
                } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }

        @Override
        public void update(Object entity, Where whereClause, UpdateEntry[] entries) {
                try {
                        Context context = aroundParser.initiateUpdate(source, entity, whereClause, entries);
                        context = DSUtils.updateGenerationProcess(context, whereClause, entries, parserPacket);
                        aroundParser.executeUpdate(context);
                } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }

        @Override
        public void remove(Object entity, Where whereClause) {
                try {
                        Context context = aroundParser.initiateRemove(source, entity, whereClause);
                        context = DSUtils.removeGenerationProcess(context, whereClause, parserPacket);
                        aroundParser.executeRemove(context);
                } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }

        @Override
        public void save(Object[] entities) {
                try {
                        aroundParser.save(source, entities);
                } catch (Exception e) {
                        throw new RuntimeException(e);
                }
        }

        @Override
        public void txBegin() {
                txManager.txBegin();
        }

        @Override
        public void txCommit() {
                txManager.txCommit();
        }

        @Override
        public void txRollback() {
                txManager.txRollback();
        }

        @Override
        public void destroy() {
                aroundParser.destroy(source);
        }
}
